﻿using System;
using System.Net;
using System.Threading;
using System.Windows;
using Kiva7.Constants;
using Kiva7.Translations;
using System.Windows.Threading;
using Kiva7.Utilities;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;

namespace Kiva7.Pages
{

    public partial class MediaControl
    {
        public MediaControl()
        {
            InitializeComponent();
        }

        private const string SpeakUri =
            "http://api.microsofttranslator.com/V2/Http.svc/Speak?appId={0}&text={1}&language={2}";


        private void UserControlLoaded(object sender,
                                       RoutedEventArgs e)
        {
            // Timer to simulate the XNA game loop (SoundEffect classes are from the XNA Framework)
            DispatcherTimer xnaDispatchTimer = new DispatcherTimer
                {
                    Interval = TimeSpan.FromMilliseconds(50)
                };

            // Call FrameworkDispatcher.Update to update the XNA Framework internals.
            xnaDispatchTimer.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };

            // Start the DispatchTimer running.
            xnaDispatchTimer.Start();
        }


        public void Speak()
        {
            if (_speakText == null
                || _speakText.Stopped)
            {
                Translation translation = DataContext as Translation;

                if (translation != null)
                {
                    if (!translation.IsTranslated)
                    {
                        SpeakXna(translation.Text, "en");
                    }
                    else
                    {
                        string code = TranslatorContext.LanguageCode();

                        SpeakXna(translation.Translated, code);
                    }
                }
            }
            else
            {
                _speakText.Stop();

            }
        }

        private SpeakText _speakText;
        public void SpeakXna(string text,
                          string languageCode)
        {
            _speakText = new SpeakText(text, languageCode);
            _speakText.SpeakFirst();
        }

        private class SpeakText
        {
            private readonly string[] _texts;
            private readonly string _languageCode;

            public SpeakText(string text,
                          string languageCode)
            {
                _languageCode = languageCode;
                _texts = text.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                for(int i=0; i<_texts.Length; i++)
                {
                    string t = _texts[i];
                    t = t.Trim();
                    if (t.EndsWith("."))
                    {
                        t = t.Substring(0, text.Length - 1);
                    }
                    _texts[i] = t;
                }
            }

            private Timer _timer;
            private SoundEffectInstance _soundInstance;
            private SoundEffectInstance _nextSoundInstance;
            private SoundEffect _sound;
            private SoundEffect _nextSound;

            private bool _stopped;
            public bool Stopped
            {
                get
                {
                    return _stopped;
                }
            }
            public void Stop()
            {
                _stopped = true;
                if (_soundInstance != null)
                {
                    _soundInstance.Stop();
                }
            }

            public void SpeakFirst()
            {
                if (_texts.Length == 0
                    || Stopped)
                {
                    return;
                }
                WebClient client = new WebClient();
                client.OpenReadCompleted += ((s,
                                              args) =>
                {
                    if (args.Error == null
                        && !_stopped)
                    {
                        _nextSound = SoundEffect.FromStream(args.Result);
                        _nextSoundInstance = _nextSound.CreateInstance();
                        SpeakNext(1);
                    }
                });

                client.OpenReadAsync(new Uri(string.Format(SpeakUri, Constant.BingAppId, _texts[0], _languageCode)));
            }

            private void SpeakNext(int index)
            {
                if (Stopped)
                {
                    _stopped = true;
                    return;
                }
                if (index >= _texts.Length)
                {
                    _nextSoundInstance.Play();
                }
                else
                {
                    WebClient client = new WebClient();
                    client.OpenReadCompleted += ((s,
                                                  args) =>
                        {
                            if (args.Error == null
                                &&
                                !_stopped)
                            {
                                _sound = _nextSound;
                                _soundInstance = _nextSoundInstance;
                                _soundInstance.Play();

                                _nextSound = SoundEffect.FromStream(args.Result);
                                _nextSoundInstance = _nextSound.CreateInstance();

                                long l = (long) _sound.Duration.TotalMilliseconds;
                                _timer = new Timer(TimerProc, index + 1, l, -1);
                            }
                            else if (args.Error != null)
                            {
                                ExceptionHandler.HandleException(args.Error);
                            }
                        });

                    client.OpenReadAsync(
                        new Uri(string.Format(SpeakUri, Constant.BingAppId, _texts[index], _languageCode)));
                }
            }

            private void TimerProc(object state)
            {
                int index = (int) state;
                if (_soundInstance.State == SoundState.Playing)
                {
                    _timer = new Timer(TimerProc, index, 50, -1);
                }
                else
                {
                    SpeakNext(index);
                }
            }
        }
    }
}